package com.micro.train.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.micro.train.entity.TrainSeat;
import com.micro.train.entity.SeatInventory;
import com.micro.train.entity.Train;
import com.micro.train.entity.Station;
import com.micro.train.repository.TrainSeatRepository;
import com.micro.train.repository.SeatInventoryRepository;
import com.micro.train.repository.TrainRepository;
import com.micro.train.repository.StationRepository;
import com.micro.train.service.TrainSeatService;
import com.micro.train.dto.TrainInventoryDTO;
import com.micro.train.service.PriceCalculationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * 火车座位服务实现类（7天滚动窗口库存管理）
 */
@Service
public class TrainSeatServiceImpl extends ServiceImpl<TrainSeatRepository, TrainSeat> implements TrainSeatService {
    
    @Autowired
    private TrainSeatRepository trainSeatRepository;
    
    @Autowired
    private SeatInventoryRepository seatInventoryRepository;
    
    @Autowired
    private TrainRepository trainRepository;
    
    @Autowired
    private StationRepository stationRepository;
    
    @Autowired
    private PriceCalculationService priceCalculationService;
    
    @Override
    public TrainSeat addSeat(TrainSeat seat) {
        trainSeatRepository.insert(seat);
        return seat;
    }
    
    @Override
    public List<TrainSeat> addSeats(List<TrainSeat> seats) {
        for (TrainSeat seat : seats) {
            trainSeatRepository.insert(seat);
        }
        return seats;
    }
    
    @Override
    public TrainSeat updateSeat(Long seatId, TrainSeat seat) {
        TrainSeat existingSeat = getSeatById(seatId);
        if (existingSeat == null) {
            throw new RuntimeException("座位不存在，ID：" + seatId);
        }
        
        seat.setSeatId(seatId);
        trainSeatRepository.updateById(seat);
        return seat;
    }
    
    @Override
    public void deleteSeat(Long seatId) {
        TrainSeat seat = getSeatById(seatId);
        if (seat == null) {
            throw new RuntimeException("座位不存在，ID：" + seatId);
        }
        trainSeatRepository.deleteById(seatId);
    }
    
    @Override
    public List<TrainSeat> getAllSeats() {
        return trainSeatRepository.selectList(null);
    }
    
    @Override
    public TrainSeat getSeatById(Long seatId) {
        return trainSeatRepository.selectById(seatId);
    }
    
    @Override
    public List<TrainSeat> getSeatsByTrainId(Long trainId) {
        return trainSeatRepository.selectByTrainId(trainId);
    }
    
    @Override
    public List<TrainSeat> getSeatsByCarriageId(Long carriageId) {
        return trainSeatRepository.selectByCarriageId(carriageId);
    }
    
    @Override
    public List<TrainSeat> getSeatsByType(Integer seatType) {
        return trainSeatRepository.selectBySeatType(seatType);
    }
    
    @Override
    public List<TrainSeat> getSeatsByTrainIdAndType(Long trainId, Integer seatType) {
        return trainSeatRepository.selectByTrainIdAndSeatType(trainId, seatType);
    }
    
    @Override
    public List<TrainSeat> getSeatsByPriceRange(BigDecimal minPrice, BigDecimal maxPrice) {
        return trainSeatRepository.selectByPriceRange(minPrice, maxPrice);
    }
    
    @Override
    @Transactional
    public Long purchaseTicket(Long trainId, Integer seatType, Integer quantity, LocalDate travelDate) {
        // 获取合适的基准日期
        LocalDate baseDate = findBaseDateForTravelDate(travelDate);
        
        // 自动初始化库存窗口（如果不存在）
        try {
            initializeInventoryWindow(trainId, baseDate);
        } catch (Exception e) {
            // 如果初始化失败，记录日志但不中断流程
            System.err.println("WARNING - 初始化库存窗口失败: " + e.getMessage());
        }
        
        // 检查库存是否足够
        Integer availableCount = getAvailableSeatCount(trainId, seatType, travelDate);
        if (availableCount < quantity) {
            throw new RuntimeException("库存不足，需要：" + quantity + "，可用：" + availableCount);
        }
        
        // 获取该类型的座位库存
        List<SeatInventory> inventories = seatInventoryRepository.selectByTrainIdAndSeatType(trainId, seatType, baseDate);
        
        // 选择可用的座位进行购买
        int purchasedCount = 0;
        Long purchasedSeatId = null; // 记录购买的座位ID
        
        for (SeatInventory inventory : inventories) {
            if (purchasedCount >= quantity) {
                break;
            }
            
            if (inventory.isAvailable(travelDate)) {
                if (inventory.markAsSold(travelDate)) {
                    seatInventoryRepository.updateById(inventory);
                    purchasedCount++;
                    
                    // 记录第一个购买的座位ID
                    if (purchasedSeatId == null) {
                        purchasedSeatId = inventory.getSeatId();
                    }
                }
            }
        }
        
        if (purchasedCount < quantity) {
            throw new RuntimeException("购买失败，实际购买：" + purchasedCount + "，需要：" + quantity);
        }
        
        // 返回实际购买的座位ID
        return purchasedSeatId != null ? purchasedSeatId : 1L;
    }
    
    @Override
    public TrainInventoryDTO getTrainInventory(Long trainId, LocalDate travelDate) {
        Train train = trainRepository.selectById(trainId);
        if (train == null) {
            throw new RuntimeException("列车不存在，ID：" + trainId);
        }
        
        Station departureStation = stationRepository.selectById(train.getDepartureStationId());
        Station terminalStation = stationRepository.selectById(train.getTerminalStationId());
        
        // 获取合适的基准日期（找到包含目标日期的7天窗口）
        LocalDate baseDate = findBaseDateForTravelDate(travelDate);
        
        // 添加调试信息
        System.out.println("DEBUG - 查询库存信息:");
        System.out.println("  列车ID: " + trainId);
        System.out.println("  旅行日期: " + travelDate);
        System.out.println("  计算出的基准日期: " + baseDate);
        
        // 获取所有座位
        List<TrainSeat> seats = getSeatsByTrainId(trainId);
        
        // 按座位类型分组统计
        Map<Integer, List<TrainSeat>> seatsByType = seats.stream()
                .collect(Collectors.groupingBy(TrainSeat::getSeatType));
        
        Map<String, TrainInventoryDTO.SeatTypeInventory> seatTypeInventories = new HashMap<>();
        int totalAvailableSeats = 0;
        
        for (Map.Entry<Integer, List<TrainSeat>> entry : seatsByType.entrySet()) {
            Integer seatType = entry.getKey();
            List<TrainSeat> typeSeats = entry.getValue();
            
            // 获取该类型的库存状态
            List<SeatInventory> inventories = seatInventoryRepository.selectByTrainIdAndSeatType(trainId, seatType, baseDate);
            
            int totalSeats = typeSeats.size();
            int availableSeats = 0;
            
            // 统计可用座位
            for (SeatInventory inventory : inventories) {
                if (inventory.isAvailable(travelDate)) {
                    availableSeats++;
                }
            }
            
            String seatTypeName = TrainSeat.SeatType.fromCode(seatType).getDescription();
            
            TrainInventoryDTO.SeatTypeInventory inventory = new TrainInventoryDTO.SeatTypeInventory();
            inventory.setSeatTypeName(seatTypeName);
            inventory.setSeatTypeCode(seatType);
            inventory.setTotalSeats(totalSeats);
            inventory.setAvailableSeats(availableSeats);
            inventory.setSoldSeats(totalSeats - availableSeats);
            inventory.setLockedSeats(0); // 新系统中没有锁定状态
            inventory.setMinPrice(typeSeats.isEmpty() ? BigDecimal.ZERO : typeSeats.get(0).getPrice());
            inventory.setMaxPrice(typeSeats.isEmpty() ? BigDecimal.ZERO : typeSeats.get(0).getPrice());
            inventory.setAveragePrice(typeSeats.isEmpty() ? BigDecimal.ZERO : typeSeats.get(0).getPrice());
            
            seatTypeInventories.put(seatTypeName, inventory);
            totalAvailableSeats += availableSeats;
        }
        
        TrainInventoryDTO dto = new TrainInventoryDTO();
        dto.setTrainId(trainId);
        dto.setTrainNumber(train.getTrainNumber());
        dto.setTrainType(train.getTrainType());
        dto.setDepartureStationName(departureStation.getStationName());
        dto.setTerminalStationName(terminalStation.getStationName());
        dto.setDepartureTime(train.getDepartureTime().toString());
        dto.setArrivalTime(train.getArrivalTime().toString());
        dto.setTotalSeats(seats.size());
        dto.setAvailableSeats(totalAvailableSeats);
        dto.setSoldSeats(seats.size() - totalAvailableSeats);
        dto.setSeatTypeInventories(seatTypeInventories);
        dto.setTravelDate(travelDate.toString());
        
        return dto;
    }
    
    @Override
    public Integer getAvailableSeatCount(Long trainId, Integer seatType, LocalDate travelDate) {
        LocalDate baseDate = findBaseDateForTravelDate(travelDate);
        
        // 自动初始化库存窗口（如果不存在）
        try {
            initializeInventoryWindow(trainId, baseDate);
        } catch (Exception e) {
            // 如果初始化失败，记录日志但不中断流程
            System.err.println("WARNING - 初始化库存窗口失败: " + e.getMessage());
        }
        
        List<SeatInventory> inventories = seatInventoryRepository.selectByTrainIdAndSeatType(trainId, seatType, baseDate);
        
        int availableCount = 0;
        for (SeatInventory inventory : inventories) {
            if (inventory.isAvailable(travelDate)) {
                availableCount++;
            }
        }
        
        return availableCount;
    }
    
    @Override
    public SeatInventory getSeatInventory(Long seatId, LocalDate baseDate) {
        return seatInventoryRepository.selectBySeatIdAndBaseDate(seatId, baseDate);
    }
    
    @Override
    public boolean updateSeatInventory(SeatInventory inventory) {
        return seatInventoryRepository.updateById(inventory) > 0;
    }
    
    @Override
    @Transactional
    public void initializeInventoryWindow(Long trainId, LocalDate baseDate) {
        // 获取列车的所有座位
        List<TrainSeat> seats = getSeatsByTrainId(trainId);
        
        // 为每个座位创建7天库存记录（如果不存在）
        List<SeatInventory> inventories = new ArrayList<>();
        for (TrainSeat seat : seats) {
            // 检查是否已存在该座位的库存记录
            SeatInventory existingInventory = seatInventoryRepository.selectBySeatIdAndBaseDate(seat.getSeatId(), baseDate);
            if (existingInventory == null) {
                // 如果不存在，则创建新的库存记录
                SeatInventory inventory = new SeatInventory();
                inventory.setSeatId(seat.getSeatId());
                inventory.setTrainId(trainId);
                inventory.setSevenDayStatus("1111111"); // 初始全部可用
                inventory.setBaseDate(baseDate);
                inventories.add(inventory);
            }
        }
        
        // 批量插入库存记录
        if (!inventories.isEmpty()) {
            seatInventoryRepository.batchInsert(inventories);
        }
    }
    
    @Override
    @Transactional
    public void rollInventoryWindow(LocalDate newBaseDate) {
        // 获取所有列车
        List<Train> trains = trainRepository.selectList(null);
        
        for (Train train : trains) {
            // 为每个列车初始化新的7天窗口（如果不存在）
            initializeInventoryWindow(train.getTrainId(), newBaseDate);
        }
        
        // 清理过期的库存记录（7天前的）
        LocalDate expireDate = newBaseDate.minusDays(7);
        cleanupExpiredInventory(expireDate);
    }
    
    @Override
    public void cleanupExpiredInventory(LocalDate expireDate) {
        seatInventoryRepository.deleteExpiredInventory(expireDate);
    }
    
    @Override
    public void cleanupInventoryByBaseDate(LocalDate baseDate) {
        // 删除指定基准日期的所有库存记录
        seatInventoryRepository.delete(new LambdaQueryWrapper<SeatInventory>()
                .eq(SeatInventory::getBaseDate, baseDate));
    }
    
    @Override
    public List<SeatInventory> getSeatInventoriesByDate(Long trainId, LocalDate travelDate) {
        LocalDate baseDate = getCurrentBaseDate();
        return seatInventoryRepository.selectByTrainIdAndBaseDate(trainId, baseDate);
    }
    
    /**
     * 获取当前基准日期（今天）
     */
    private LocalDate getCurrentBaseDate() {
        return LocalDate.now();
    }
    
    /**
     * 根据旅行日期找到对应的基准日期
     * 基准日期是7天窗口的起始日期
     */
    private LocalDate findBaseDateForTravelDate(LocalDate travelDate) {
        // 计算旅行日期距离今天的天数
        LocalDate today = LocalDate.now();
        long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(today, travelDate);
        
        // 如果旅行日期在今天或之前，使用今天的基准日期
        if (daysDiff <= 0) {
            return today;
        }
        
        // 如果旅行日期在未来7天内，使用今天的基准日期
        if (daysDiff < 7) {
            return today;
        }
        
        // 如果旅行日期超过7天，需要计算对应的基准日期
        // 每7天一个窗口，基准日期是窗口的第一天
        // 修正：计算旅行日期所在的7天窗口的起始日期
        long windowIndex = (daysDiff - 1) / 7; // 减1是为了让第7天也属于第一个窗口
        return today.plusDays(windowIndex * 7);
    }
}
